package cn.shop.utils;

import cn.hutool.core.util.ArrayUtil;
import cn.hutool.core.util.ModifierUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.ReflectUtil;

import java.lang.reflect.Field;
import java.util.Collection;
import java.util.Map;
import java.util.Objects;
import java.util.function.Function;

/**
 * @author zhy
 */
@SuppressWarnings("unused")
public class Utils {
	
	public static boolean isEmpty(final CharSequence string) {
		return string == null || string.length() == 0;
	}
	
    /**
     * Null-safe check if the specified collection is empty.
     * <p>
     * Null returns true.
     * 
     * @param coll  the collection to check, may be null
     * @return true if empty or null
     */
    public static <E> boolean isEmpty(final Collection<E> coll) {
        return coll == null || coll.isEmpty();
    }

    /**
     * Null-safe check if the specified map is empty.
     * <p>
     * Null returns true.
     * 
     * @param map  the map to check, may be null
     * @return true if empty or null
     */
    public static <K, V> boolean isEmpty(final Map<K, V> map) {
        return map == null || map.isEmpty();
    }
    
    public static boolean isNotEmpty(final CharSequence string) {
    	return string != null && string.length() > 0;
    }
    
    /**
     * Null-safe check if the specified collection is not empty.
     * <p>
     * Null returns false.
     * 
     * @param coll  the collection to check, may be null
     * @return true if non-null and non-empty
     */
    public static <E> boolean isNotEmpty(final Collection<E> coll) {
        return coll != null && !coll.isEmpty();
    }
	
    /**
     * Null-safe check if the specified map is not empty.
     * <p>
     * Null returns false.
     * 
     * @param map  the map to check, may be null
     * @return true if non-null and non-empty
     */
    public static <K, V> boolean isNotEmpty(final Map<K, V> map) {
        return map != null && !map.isEmpty();
    }

    /**
     * <p>Returns a default value if the object passed is
     * <code>null</code>.</p>
     * 
     * <pre>
     * Utils.defaultIfNull(null, null)      = null
     * Utils.defaultIfNull(null, "")        = ""
     * Utils.defaultIfNull(null, "zz")      = "zz"
     * Utils.defaultIfNull("abc", *)        = "abc"
     * Utils.defaultIfNull(Boolean.TRUE, *) = Boolean.TRUE
     * </pre>
     *
     * @param obj  the <code>Object</code> to test, may be <code>null</code>
     * @param defaultObj  the default value to return, may be <code>null</code>
     * @return <code>object</code> if it is not <code>null</code>, defaultValue otherwise
     */
    public static <T> T defaultIfNull(final T obj, final T defaultObj) {
    	return obj != null ? obj : defaultObj;
    }
    
    /**
     * <p>Returns either the passed in CharSequence, or if the CharSequence is
     * empty or {@code null}, the value of {@code defaultStr}.</p>
     *
     * <pre>
     * StringUtils.defaultIfEmpty(null, "NULL")  = "NULL"
     * StringUtils.defaultIfEmpty("", "NULL")    = "NULL"
     * StringUtils.defaultIfEmpty(" ", "NULL")   = " "
     * StringUtils.defaultIfEmpty("bat", "NULL") = "bat"
     * StringUtils.defaultIfEmpty("", null)      = null
     * </pre>
     * @param <T> the specific kind of CharSequence
     * @param str  the CharSequence to check, may be null
     * @param defaultStr  the default CharSequence to return
     *  if the input is empty ("") or {@code null}, may be null
     * @return the passed in CharSequence, or the default
     */
    public static <T extends CharSequence> T defaultIfEmpty(final T str, final T defaultStr) {
        return isEmpty(str) ? defaultStr : str;
    }

    /**
     * 获取列表的第一个元素。如果列表为空，返回null。
     */
    public static <T> T first(final Collection<T> coll) {
        return (coll == null || coll.isEmpty()) ? null : coll.iterator().next();
    }
    
    /**
     * 运行该函数，返回其结果，如果有异常抛出，返回null。
     * 
     * @param <T> 参数类型
     * @param <U> 结果类型
     * @param func 一元函数
     * @param arg 参数
     * @return 如果函数运行无异常，其结果，否则null
     */
    public static <T, U> U nullIfThrow(Function<T, U> func, T arg) {
    	Objects.requireNonNull(func);
    	U value = null;
    	try {
    		value = func.apply(arg);
    	} catch (Throwable t) {
    		// ignore
    	}
    	return value;
    }
    
    /**
     * 检查并返回合法的offset值（非负整数）。
     * @return 合法的offset值
     */
    public static int checkOffset(int offset) {
    	return Math.max(offset, 0);
    }
    
    /**
     * 检查并返回合法的offset值（非负整数），offset不能超过指定上限。
     * @param maximum offset值的上限（含）
     * @return 合法的offset值
     */
    public static int checkOffset(int offset, int maximum) {
    	assert maximum >= 0 : "maximum must be non-negative";
    	return offset < 0 ? 0 : Math.min(offset, maximum);
    }
    
    /**
     * 检查并返回合法的limit值（正数），limit不能超过指定上限，非正值等同于上限。
     * @param maximum limit值的上限（含）。当limit是非正数时取该上限
     * @return 合法的limit值
     */
    public static int checkLimit(int limit, int maximum) {
    	assert maximum >= 0 : "maximum must be non-negative";
    	return limit <= 0 ? maximum : Math.min(limit, maximum);
    }

    public static boolean isEmpty(Object bean, String... ignoreFiledNames) {
        if (null != bean) {
            for (Field field : ReflectUtil.getFields(bean.getClass())) {
                if (ModifierUtil.isStatic(field)) {
                    continue;
                }
                if (!ArrayUtil.contains(ignoreFiledNames, field.getName())
                        && ObjectUtil.isNotEmpty(ReflectUtil.getFieldValue(bean, field))) {
                    return false;
                }
            }
        }
        return true;
    }
}
